﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.ApplicationServer.Http.Dispatcher;
using System.Net.Http;
using System.Net;
using ApiPrototype.Models;
using log4net;

namespace ApiPrototype.Handlers
{
    public class ApiErrorHandler : HttpErrorHandler
	{
        private static ILog logger = LogManager.GetLogger(typeof(ApiErrorHandler));

		protected override bool OnTryProvideResponse(Exception ex, ref HttpResponseMessage message)
		{
            var error = new ApiError();
            Exception logException = null;

            /* Respond with the format that was requested, we have to do this because a bug in the framework
             * ignores the previousformat negotiations, same goes for the formatters below ( default formatters
             * are used instead of those defined in the WebApiConfiguration)
             */
            var contentType = "";
            try
            {
                contentType = HttpContext.Current.Request.AcceptTypes.FirstOrDefault();
                if (string.IsNullOrWhiteSpace(contentType))
                    contentType = "application/json";
            }
            catch
            {
                contentType = "application/json";
            }

            if (ex is ApiException)
            {
                var apiEx = ex as ApiException;
                logException = apiEx.InnerException;

                error.Code = apiEx.Code;
                error.Message = apiEx.Message;
            }
            else if (ex is HttpResponseException)
            {
                var httpEx = ex as HttpResponseException;
                logException = httpEx.InnerException;

                error.Code = httpEx.Response.StatusCode;
                error.Message = httpEx.Response.ReasonPhrase;
            }
            else
            {
                logException = ex;
                error.Code = HttpStatusCode.InternalServerError;
                error.Message = "Internal Server Error";
            }
              
            var content = new ObjectContent<ApiError>(error);
            content.Formatters.Insert(0, MvcApplication.jsonNetFormatter);
            try
            {
                content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType);
            }
            catch
            {
                content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
            }

            /* We always send OK. This way the client application knows the errors were handled server-side
             * and it's safe to parse the response. Other status codes would indicate errors that are uncaught here
             * and thus not properly formatted. The exception to this rule is 401 Unauthorized.
             */
            message = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = content
            };

            /*
             * Forefront returns custom error pages, keeping StatusCode.OK
             */ 
            if (error.Code == HttpStatusCode.Unauthorized)
            {
                message.StatusCode = HttpStatusCode.Unauthorized;
                message.Headers.Add("WWW-Authenticate", "Basic realm=\"Secure Area\"");
            }

            logger.Error(error.Message);
            if (logException != null)
                logger.Debug(error.Message, logException);
			
			return true;
		}
	}
}